package com.qdlc.p2p.biz.service.impl;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.qdlc.p2p.biz.service.BorrowRepaymentService;
import com.qdlc.p2p.biz.task.ConcurrentUtil;
import com.qdlc.p2p.biz.util.IdcardUtils;
import com.qdlc.p2p.common.constant.BorrowRepaymentStatus;
import com.qdlc.p2p.common.constant.BorrowType;
import com.qdlc.p2p.common.constant.Global;
import com.qdlc.p2p.common.util.BigDecimalUtil;
import com.qdlc.p2p.common.util.DateUtil;
import com.qdlc.p2p.common.util.MailUtil;
import com.qdlc.p2p.common.util.StringUtil;
import com.qdlc.p2p.dal.common.SystemConfigHelper;
import com.qdlc.p2p.dal.common.model.jpa.OrderFilter.OrderType;
import com.qdlc.p2p.dal.common.model.jpa.PageDataList;
import com.qdlc.p2p.dal.common.model.jpa.QueryParam;
import com.qdlc.p2p.dal.common.model.jpa.SearchFilter;
import com.qdlc.p2p.dal.common.model.jpa.SearchFilter.Operators;
import com.qdlc.p2p.dal.dao.BorrowCollectionDao;
import com.qdlc.p2p.dal.dao.BorrowOverdueDao;
import com.qdlc.p2p.dal.dao.BorrowRepaymentDao;
import com.qdlc.p2p.dal.dto.Borrow;
import com.qdlc.p2p.dal.dto.BorrowOverdue;
import com.qdlc.p2p.dal.dto.BorrowRepayment;
import com.qdlc.p2p.dal.dto.Operator;
import com.qdlc.p2p.dal.model.BorrowModel;
import com.qdlc.p2p.dal.model.BorrowRepaymentModel;

@Service("borrowRepaymentService")
public class BorrowRepaymentServiceImpl implements BorrowRepaymentService {

    @Resource
    private BorrowRepaymentDao borrowRepaymentDao;

    @Resource
    private BorrowOverdueDao borrowOverdueDao;

    @Resource
    private BorrowCollectionDao borrowCollectionDao;

    @Override
    public PageDataList<BorrowRepaymentModel> list(BorrowRepaymentModel model, String searchName) {
        QueryParam param = QueryParam.getInstance();
        if (model != null) {
            if (model.getVouchFirm() != null) {
                param.addParam("borrow.vouchFirm", model.getVouchFirm());
            } else {
                if (StringUtil.isNotBlank(searchName)) {
                    SearchFilter orFilter1 = new SearchFilter("borrow.name", Operators.LIKE, searchName.trim());
                    SearchFilter orFilter2 = new SearchFilter("user.realName", Operators.LIKE, searchName.trim());
                    SearchFilter orFilter3 = new SearchFilter("user.userName", Operators.LIKE, searchName.trim());
                    param.addOrFilter(orFilter1, orFilter2, orFilter3);
                } else {
                    if (model.getBorrowId() > 0) {
                        param.addParam("borrow.id", model.getBorrowId());
                    }
                    if (model.getUser() != null && model.getUser().getUserId() > 0) {
                        param.addParam("user.userId", model.getUser().getUserId());
                    }
                    if (model.getStatus() != 99) {
                        param.addParam("status", model.getStatus());
                    }
                    if (StringUtil.isNotBlank(model.getUserName())) {
                        param.addParam("user.userName", Operators.LIKE, model.getUserName().trim());
                    }
                    if (StringUtil.isNotBlank(model.getRealName())) {
                        param.addParam("user.realName", Operators.LIKE, model.getRealName().trim());
                    }
                    Date d = DateUtil.getDate(System.currentTimeMillis() / 1000 + "");
                    if (model.getTime() == 7) {
                        param.addParam("repaymentTime", Operators.GTE, d);
                        param.addParam("repaymentTime", Operators.LTE, DateUtil.rollDay(d, 7));
                    } else if (model.getTime() > 0 && model.getTime() < 4) {
                        param.addParam("repaymentTime", Operators.GTE, d);
                        param.addParam("repaymentTime", Operators.LTE, DateUtil.rollMon(d, model.getTime()));
                    }
                    if (StringUtil.isNotBlank(model.getStartTime())) {
                        Date start = DateUtil.valueOf(model.getStartTime() + " 00:00:00");
                        param.addParam("repaymentTime", Operators.GTE, start);
                    }
                    if (StringUtil.isNotBlank(model.getEndTime())) {
                        Date end = DateUtil.valueOf(model.getEndTime() + " 23:59:59");
                        param.addParam("repaymentTime", Operators.LTE, end);
                    }
                }
            }
            if (model.isLate()) {
                if (model.getType() != 0) {
                    param.addParam("borrow.type", model.getType());
                }
                param.addParam("repaymentTime", Operators.LTE, DateUtil.getNow());
                param.addParam("borrow.type", Operators.NOTEQ, BorrowType.TYPE_SECOND);
                SearchFilter orFilter1 = new SearchFilter("repaymentYesTime", Operators.PROPERTY_GT, "repaymentTime");
                SearchFilter orFilter2 = new SearchFilter("repaymentYesAccount", Operators.EQ, 0);
                param.addOrFilter(orFilter1, orFilter2);
            }
            param.addPage(model.getPage(), model.getSize());
        }
        param.addOrder(OrderType.ASC, "repaymentTime");

        PageDataList<BorrowRepayment> pageDataList = borrowRepaymentDao.findPageList(param);
        PageDataList<BorrowRepaymentModel> pageDateList = new PageDataList<BorrowRepaymentModel>();
        List<BorrowRepaymentModel> list = new ArrayList<BorrowRepaymentModel>();
        pageDateList.setPage(pageDataList.getPage());
        if (pageDataList.getList().size() > 0) {
            for (int i = 0; i < pageDataList.getList().size(); i++) {
                BorrowRepayment r = pageDataList.getList().get(i);
                BorrowRepaymentModel rm = BorrowRepaymentModel.instance(r);
                rm.setBorrowId(r.getBorrow().getId());
                rm.setBorrowName(r.getBorrow().getName());
                rm.setUserName(r.getUser().getUserName());
                rm.setRealName(r.getUser().getRealName());
                rm.setMobilePhone(r.getUser().getMobilePhone());
                rm.setTimeLimit(r.getBorrow().getTimeLimit());
                rm.setType(r.getBorrow().getType());
                rm.setBorrowStyle(r.getBorrow().getStyle()); // 设置还款方式
                rm.setBorrow(null);
                rm.setUser(null);
                rm.setLateDays(DateUtil.daysBetween(r.getRepaymentTime(), DateUtil.getNow()));
                rm.setLateInterest(r.getLateInterest());
                list.add(rm);
            }
        }
        pageDateList.setList(list);
        return pageDateList;
    }

    @Override
    public PageDataList<BorrowRepaymentModel> getList(BorrowRepaymentModel model) {
        PageDataList<BorrowRepayment> pageDataList = borrowRepaymentDao.getList(model);
        PageDataList<BorrowRepaymentModel> pageDateList = new PageDataList<BorrowRepaymentModel>();
        List<BorrowRepaymentModel> list = new ArrayList<BorrowRepaymentModel>();
        pageDateList.setPage(pageDataList.getPage());
        if (pageDataList.getList().size() > 0) {
            for (int i = 0; i < pageDataList.getList().size(); i++) {
                //获取当前标 待还记录中 最小期数
                BorrowRepayment r = pageDataList.getList().get(i);
                int period = borrowRepaymentDao.getMinPeriod(r.getBorrow().getId());
                BorrowRepaymentModel rm = BorrowRepaymentModel.instance(r);
                rm.setBorrowId(r.getBorrow().getId());
                rm.setBorrowUuid(r.getBorrow().getUuid());
                rm.setBorrowName(r.getBorrow().getName());
                rm.setUserName(r.getUser().getUserName());
                rm.setRealName(r.getUser().getRealName());
                rm.setMobilePhone(r.getUser().getMobilePhone());
                rm.setTimeLimit(r.getBorrow().getTimeLimit());
                rm.setType(r.getBorrow().getType());
                rm.setBorrowStyle(r.getBorrow().getStyle()); // 设置还款方式
                rm.setBorrow(null);
                rm.setUser(null);
                rm.setLateInterest(r.getLateInterest());
                rm.setLateDays(r.getLateDays());
                if (r.getStatus() == BorrowRepaymentStatus.STATUS_WAIT_REPAY) {  //当是未还款借款，判断多期的时候，只有最近一期还款计划显示还款链接
                    if (period == r.getPeriod()) {
                        rm.setIsRepayentStatus(1);
                    } else {
                        rm.setIsRepayentStatus(0);
                    }
                }
                list.add(rm);
            }
        }
        pageDateList.setList(list);
        return pageDateList;
    }

    @Override
    public BorrowRepayment findById(long repayId) {
        return borrowRepaymentDao.findById(repayId);
    }

    @Override
    public double getUserBorrowRepayTotal(long userId) {
        return borrowRepaymentDao.getUserBorrowRepayTotal(userId);
    }

    @Override
    public BorrowRepaymentModel getReapyStatistics(long userId) {
        BorrowRepaymentModel bm = borrowRepaymentDao.getRepayStatistics(userId);
        BorrowRepayment br = borrowRepaymentDao.getNextRepayByUserId(userId);
        if (br != null) {
            bm.setBorrowId(br.getBorrow().getId());
            bm.setNextRepayTime(br.getRepaymentTime());
            bm = borrowRepaymentDao.getBRMByCollectTime(bm, br.getRepaymentTime(), userId);
        }
        double jan = borrowRepaymentDao.getRepayByMonth(1, userId);
        double feb = borrowRepaymentDao.getRepayByMonth(2, userId);
        double mar = borrowRepaymentDao.getRepayByMonth(3, userId);
        double apr = borrowRepaymentDao.getRepayByMonth(4, userId);
        double may = borrowRepaymentDao.getRepayByMonth(5, userId);
        double jun = borrowRepaymentDao.getRepayByMonth(6, userId);
        double jul = borrowRepaymentDao.getRepayByMonth(7, userId);
        double aug = borrowRepaymentDao.getRepayByMonth(8, userId);
        double sep = borrowRepaymentDao.getRepayByMonth(9, userId);
        double oct = borrowRepaymentDao.getRepayByMonth(10, userId);
        double nov = borrowRepaymentDao.getRepayByMonth(11, userId);
        double dec = borrowRepaymentDao.getRepayByMonth(12, userId);
        bm.getRepayData().put("jan", jan);
        bm.getRepayData().put("feb", feb);
        bm.getRepayData().put("mar", mar);
        bm.getRepayData().put("apr", apr);
        bm.getRepayData().put("may", may);
        bm.getRepayData().put("jun", jun);
        bm.getRepayData().put("jul", jul);
        bm.getRepayData().put("aug", aug);
        bm.getRepayData().put("sep", sep);
        bm.getRepayData().put("oct", oct);
        bm.getRepayData().put("nov", nov);
        bm.getRepayData().put("dec", dec);
        return bm;
    }

    @Override
    public void overdue(BorrowRepayment borrowRepayment, Operator operator) {
        Borrow borrow = borrowRepayment.getBorrow();
        BorrowOverdue borrowOverdue = new BorrowOverdue();
        borrowOverdue.setOperator(operator);
        borrowOverdue.setOverdueAccount(borrowRepayment.getRepaymentAccount());
        borrowOverdue.setOverdueTime(DateUtil.getNow());
        borrowOverdue.setRepaymentAccount(borrowRepayment.getRepaymentAccount());
        borrowOverdue.setRepaymentTime(borrowRepayment.getRepaymentTime());
        borrowOverdue.setUserName(borrowRepayment.getUser().getUserName());
        borrowOverdueDao.save(borrowOverdue);
        // 设置web_status=3
        borrowRepayment.setWebStatus(BorrowRepayment.WEB_STATUS_INSTEAD);
        borrowRepayment = borrowRepaymentDao.update(borrowRepayment);
        Global.setTransfer("borrow", borrow);
        ConcurrentUtil.overdue(borrowRepayment);
    }

    @Override
    public int count() {

        String date = DateUtil.dateStr2(DateUtil.getNow());
        Date start = DateUtil.valueOf(date + " 00:00:00");
        Date end = DateUtil.valueOf(date + " 23:59:59");
        QueryParam param = QueryParam.getInstance()
                .addParam("status", 0)
                .addParam("repaymentTime", Operators.GT, start)
                .addParam("repaymentTime", Operators.LT, end);
        return borrowRepaymentDao.countByCriteria(param);
    }

    @Override
    public void updateLateInterest(BorrowRepayment borrowRepayment) {
        try {
            // 计算逾期利息
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            Date nowTime = format.parse(DateUtil.dateStr2(DateUtil.getNow()));
            Date repaymentTime = format.parse(DateUtil.dateStr2(borrowRepayment.getRepaymentTime()));

            long day = nowTime.getTime() - repaymentTime.getTime();
            int days = (int) (day / (24 * 60 * 60 * 1000));
            double lateInterest = 0;
            int allFreeOverdueDay = SystemConfigHelper.getIntegerValue(SystemConfigHelper.Nid.ALL_FREE_OVERDUE_DAY);//？天内不产生任何罚息
            if (days <= allFreeOverdueDay) {
                days = 0;
            } else {
                days = days - allFreeOverdueDay;
            }
            if (days > 0) {
                double overdue = SystemConfigHelper.getDoubleValue(SystemConfigHelper.Nid.OVERDUE_FEE);
                int FreeOverdueDay = SystemConfigHelper.getIntegerValue(SystemConfigHelper.Nid.FREE_OVERDUE_DAY);//？天内免逾期罚息
                if (days <= FreeOverdueDay) {
                    double capital = borrowRepayment.getCapital();
                    lateInterest = BigDecimalUtil.mul(BigDecimalUtil.mul(capital + borrowRepayment.getInterest(), days), overdue);
                } else if (days > FreeOverdueDay) {
                    double capital = borrowRepaymentDao.getRemainderCapital(borrowRepayment.getBorrow().getId());
                    double interest = borrowRepaymentDao.getRemainderInterest(borrowRepayment.getBorrow().getId());
                    lateInterest = BigDecimalUtil.mul(BigDecimalUtil.mul(capital + interest, days), overdue);
                }
                borrowRepayment.setLateDays(days);
                borrowRepayment.setLateInterest(lateInterest);
                borrowRepaymentDao.update(borrowRepayment);

                // 更新collection逾期信息
                double lateRate = lateInterest / borrowRepayment.getRepaymentAccount();
                borrowCollectionDao.updateLateInterest(borrowRepayment.getBorrow().getId(), borrowRepayment.getPeriod(), days, lateRate);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            MailUtil.sendMail("逾期还款出错", ex);
        }
    }

    public List<BorrowRepayment> findTodayExpiresRepayments() {
        String noticeTimeStr = DateUtil.dateStr2(DateUtil.rollDay(DateUtil.getNow(), 3));
        Date noticeTimeStart = DateUtil.valueOf(noticeTimeStr + " 00:00:00");
        Date noticeTimeEnd = DateUtil.valueOf(noticeTimeStr + " 23:59:59");
        QueryParam param = QueryParam.getInstance();
        param.addParam("repaymentTime", Operators.GTE, noticeTimeStart);
        param.addParam("repaymentTime", Operators.LTE, noticeTimeEnd);
        param.addParam("status", BorrowRepaymentStatus.STATUS_WAIT_REPAY);
        param.addParam("webStatus", BorrowRepayment.WEB_STATUS_NORMAL);
        return borrowRepaymentDao.findByCriteria(param);
    }

    @Override
    public List<BorrowRepayment> findWaitRepay() {
        return borrowRepaymentDao.findWaitRepay();
    }

    @Override
    public double getRemainderAccount() {
        return borrowRepaymentDao.getRemainderAccount();
    }

    @Override
    public List<BorrowRepayment> getRepaymentByBorrowId(long borrowId) {
        QueryParam param = QueryParam.getInstance();
        param.addParam("borrow.id", borrowId);
        return borrowRepaymentDao.findByCriteria(param);
    }

    @Override
    public int getUrgeCount(long userId) {
        QueryParam param = QueryParam.getInstance();
        param.addParam("borrow.vouchFirm.userId", userId);
        param.addParam("status", 0);
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DATE, 7);
        param.addParam("repaymentTime", Operators.GT, DateUtil.getNow());
        param.addParam("repaymentTime", Operators.LT, c.getTime());
        return borrowRepaymentDao.countByCriteria(param);
    }

    @Override
    public PageDataList<BorrowRepaymentModel> getCollectionList(BorrowModel model) {
        QueryParam param = QueryParam.getInstance();
//        if (StringUtil.isNotBlank(model.getBorrowName())) {
//            param.addParam("borrow.name", Operators.LIKE, model.getBorrowName());
//        }
        Date now = DateUtil.getNow();
        if (StringUtil.isNotBlank(model.getUserName())) {
            param.addParam("borrow.user.userName", Operators.LIKE, model.getUserName().trim());
        }
        if (model.getTime() == 7) {
            param.addParam("borrow.addTime", Operators.GT, DateUtil.rollDay(DateUtil.getNow(), -model.getTime()));
        } else if (model.getTime() != 0) {
            param.addParam("borrow.addTime", Operators.GT, DateUtil.rollMon(DateUtil.getNow(), -model.getTime()));
        }
        if (StringUtil.isNotBlank(model.getStartTime())) {
            Date startTime = DateUtil.valueOf(model.getStartTime() + " 00:00:00");
            param.addParam("borrow.addTime", Operators.GT, startTime);
        }
        if (StringUtil.isNotBlank(model.getEndTime())) {
            Date endTime = DateUtil.valueOf(model.getEndTime() + " 23:59:59");
            param.addParam("addTime", Operators.LT, endTime);
        }
        param.addParam("borrow.vouchFirm.userId", model.getVouchFirmId());
        param.addParam("status", 0);
        param.addParam("repaymentTime", Operators.GT, now);
        param.addParam("repaymentTime", Operators.LT, DateUtil.rollDay(now, 7));
        param.addPage(model.getPage(), model.getRows());
        PageDataList<BorrowRepayment> pageDataList = borrowRepaymentDao.findPageList(param);
        PageDataList<BorrowRepaymentModel> pageDateList = new PageDataList<BorrowRepaymentModel>();
        List<BorrowRepaymentModel> list = new ArrayList<BorrowRepaymentModel>();
        pageDateList.setPage(pageDataList.getPage());
        if (pageDataList.getList().size() > 0) {
            for (int i = 0; i < pageDataList.getList().size(); i++) {
                BorrowRepayment r = pageDataList.getList().get(i);
                BorrowRepaymentModel rm = BorrowRepaymentModel.instance(r);
                BorrowModel b = BorrowModel.instance(rm.getBorrow());
                rm.setUserName(b.getUser().getUserName());
                rm.setMobilePhone(b.getUser().getMobilePhone());
                b.setUser(null);
                rm.setBorrow(b.prototype());
                rm.setUser(null);
                rm.setRealRepayer(null);
                int lastDays = DateUtil.daysBetween(now, rm.getRepaymentTime());
                rm.setLastDays(lastDays);
                list.add(rm);
            }
        }
        pageDateList.setList(list);
        return pageDateList;
    }

    @Override
    public BorrowRepayment find(long id) {
        return borrowRepaymentDao.find(id);
    }

    @Override
    public double[] getOverdueByDate(String date) {
        return borrowRepaymentDao.getOverdueByDate(date);
    }

    @Override
    public double getOverdueByTypeAndDate(int type, String date) {
        return borrowRepaymentDao.getOverdueByTypeAndDate(type, date);
    }

    @Override
    public int[] getOverdueInfoByDate(String date) {
        int one = 0;
        int two = 0;
        int three = 0;
        int four = 0;
        int five = 0;
        int manCount = 0;
        int womanCount = 0;
        int[] arry = new int[7];
        List<String> cardIds = borrowRepaymentDao.getOverdueCardIdsByDate(date);
        for (String cardId : cardIds) {
            String year = cardId.substring(6, 10);
            int currentYear = Calendar.getInstance().get(Calendar.YEAR);
            int age = currentYear - Integer.parseInt(year);
            if (age >= 10 && age < 20) {
                one++;
            } else if (age >= 20 && age < 30) {
                two++;
            } else if (age >= 30 && age < 40) {
                three++;
            } else if (age >= 40 && age < 50) {
                four++;
            } else if (age > 50) {
                five++;
            }
            int length = cardId.length();
            char sexNum;
            if (length == 15) {
                sexNum = cardId.charAt(length - 1);
            } else {
                sexNum = cardId.charAt(length - 2);
            }
            // 获取性别 1:男,0:女
            int sex = sexNum % 2;
            if (sex == 0) {
                womanCount++;
            } else {
                manCount++;
            }
        }
        arry[0] = one;
        arry[1] = two;
        arry[2] = three;
        arry[3] = four;
        arry[4] = five;
        arry[5] = womanCount;
        arry[6] = manCount;
        return arry;
    }

    @Override
    public Object[][] getOverdueAreaDistributedByDate(String date) {
        List<String> cardIds = borrowRepaymentDao.getOverdueCardIdsByDate(date);
        Map<String, Integer> map = new HashMap<String, Integer>();
        for (String cardId : cardIds) {
            String province = IdcardUtils.getProvinceByIdCard(cardId);
            int count = 1;
            if (map.containsKey(province)) {
                count = map.get(province) + 1;
            }
            map.put(province, count);
        }
        Collection<Integer> coll = map.values();
        Set<String> set = map.keySet();
        Object[] provinces = set.toArray();
        Object[] counts = coll.toArray();
        Object[][] result = new Object[2][counts.length];
        result[0] = provinces;
        result[1] = counts;
        return result;
    }


}
